﻿#include"XQHttp.h"
#include"XQCoding.h"
#ifdef THIRDPARTY
#include"XQZipPack.hpp"
#endif
#include<iostream>
#include<QSslConfiguration>
#include<QEventLoop>
#include<QDebug>
void XQHttp::send()
{
	m_nSel = -1;
	m_chunked = false;
	m_content.clear();
	m_buff.clear();
	m_RecvHead.clear();
	sendHead(m_SendHead);
}
void XQHttp::getHost(const QString& url, XQHttpHeadRecv& SendRequest)
{
	QString host;
	int port = 0;
	int nSel1 = url.indexOf("//");
	if (nSel1 < 0)
	{
		qWarning() << "url错误";
		return;
	}
	int nSel2 = url.indexOf(":", nSel1 + 2);
	int nSel3 = url.indexOf("/", nSel1 + 2);
	if (nSel2 < 0 && nSel3 < 0)//只有域名
	{
		host = url.mid(nSel1 + 2);
	}
	if (nSel2 > 0)
	{
		host = url.mid(nSel1 + 2, nSel2 - nSel1 - 2);
		QString temp = url.mid(nSel2 + 1, nSel3 - nSel2);
		port = temp.toInt();
	}
	else
	{
		host = url.mid(nSel1 + 2, nSel3 - nSel1 - 2);
	}
	if (port == 0)
	{
		int nSel = url.indexOf("https");
		if (nSel !=-1)
			port = 443;
		else
			port = 80;
	}
	SendRequest.setHost(host, port);
	if (nSel3 > 0)
		SendRequest.setResPath(url.mid(nSel3));
	else
		SendRequest.setResPath("/");
}
long int XQHttp::sendHead(XQHttpHeadSend& SendRequest)
{
	/*std::cout<<SendRequest.toString().toLocal8Bit().toStdString();*/
	int sendSize =write(SendRequest.toString().toUtf8());
	/*qWarning() <<"发送成功:"<<sendSize<<"字节";*/
	return sendSize;
}
void XQHttp::recvData()
{
	m_buff += readAll(); 
	if(m_RecvHead.isEmpty())
	{
		auto head = header_recv();
		if (!head.isEmpty())
		{
			m_RecvHead.setHeader(head);
			if (m_RecvHead.header.value("Transfer-Encoding") == "chunked")
			{
				m_chunked = true;
				m_nSel = m_buff.indexOf("\r\n\r\n") + 4;
			}
			//qInfo() << m_buff;
		}
	}
	if (!m_RecvHead.isEmpty())
	{
		if (m_chunked)
		{
			while (m_nSel<m_buff.size())
			{
				auto len = currentChunkedLength();
				if (len > 0)
				{
					auto data = currentContent(len);
					if (data.isEmpty())
						break;//数据不全继续等待接收
					m_content += data;
				}
				else
				{
					finish_init();
					break;
				}
			}
		}
		else
		{
			auto len = m_RecvHead.ContentLength();
			if (/*len!=-1&&*/len <= currentContentLength())
			{
				int nSel = m_buff.indexOf("\r\n\r\n");
				if (nSel != -1)
					m_content= m_buff.mid(nSel + 4);
				finish_init();
			}
		}
		
	}
}
qint64 XQHttp::currentChunkedLength()
{
	int nSel = m_buff.indexOf("\r\n\r\n");
	if (nSel == -1)
		return -1;
	nSel = m_buff.indexOf("\r\n", m_nSel);
	auto n = m_buff.mid(m_nSel, nSel- m_nSel);
	//m_nSel= nSel+2;
	bool ok;
	qint64 decimal = n.toLongLong(&ok, 16);
	if(ok)
		return decimal;
	return -1;
}
QByteArray XQHttp::currentContent(qint64 size)
{
	int nSel = m_buff.indexOf("\r\n\r\n");
	if (nSel == -1||size<=0)
		return QByteArray();
	nSel = m_buff.indexOf("\r\n", m_nSel)+2;
	if(m_buff.size()> m_nSel+size+1)
	{
		m_nSel = nSel+size+2;
		return m_buff.mid(nSel, size);
	}
	else
	{
		return QByteArray();
	}
}
void XQHttp::finish_init()
{
	deflate();
	emit finish();//已经获取到全部内容了
}
void XQHttp::deflate()
{
	if (m_RecvHead.header.value("Content-Encoding") == "deflate")
	{//需要解压
#ifdef THIRDPARTY
		m_content = XQZipPack::decompress(m_content);
#endif
	}
}
void XQHttp::init()
{
	//链接上的时候,把请求发过去
	connect(this, &QAbstractSocket::connected, [this] {
		QString host = m_SendHead.host();
		int port = m_SendHead.port();
		m_lastHost = host;
		m_lastPort = port;
		send(); });
	//与服务器链接断开了,表示一次请求完成了
	connect(this, &XQHttp::disconnected, [this] {emit finish(); });
	//可以读取的时候
	connect(this, &QIODevice::readyRead,this,&XQHttp::recvData);
	//错误处理
	connect(this, &QTcpSocket::errorOccurred, this,&XQHttp::error,Qt::QueuedConnection);
}
XQHttp::XQHttp()
{
	init();
}
XQHttp::~XQHttp()
{
	close();
}
void XQHttp::get(const QString& url)
{
	//// 设置 SSL/TLS 配置
	//setSslConfiguration(sslConfig);
	QSslConfiguration sslConfig = sslConfiguration();
	sslConfig.setProtocol(QSsl::TlsV1_2);
	setSslConfiguration(sslConfig);


	m_SendHead.setMethod();
	getHost(url, m_SendHead);
	if (state() == QAbstractSocket::ConnectedState)
	{//已经连接上了
		QString host = m_SendHead.host();
		int port = m_SendHead.port();
		if (host == m_lastHost && port == m_lastPort)
		{//需要连接的保持不变直接发送请求
			send();
		}
	}
	else
	{//连接新的主机
		close();
		if (m_SendHead.port() == 80)
			connectToHost(m_SendHead.host(), m_SendHead.port());
		else if (m_SendHead.port() == 443)
			connectToHostEncrypted(m_SendHead.host(), m_SendHead.port());
	}
}

void XQHttp::wait()
{
	QEventLoop loop;
	connect(this,&XQHttp::finish,&loop,&QEventLoop::quit);
	//错误处理
	connect(this, &QTcpSocket::errorOccurred, &loop, &QEventLoop::quit);
	loop.exec();
}

void XQHttp::showErrorToCmd(bool on)
{
	m_showError = on;
}

void XQHttp::error(QAbstractSocket::SocketError socketError)
{
	if (m_showError)
	   qWarning() << socketError+">"+ errorString();
}

void XQHttp::GbkToUtf8()
{
	m_content = QCoding::GbkToUtf8(m_content);
}

QString XQHttp::text()
{
	return content();
}

QByteArray XQHttp::content() const
{
	//if (m_chunked)
	{
		return m_content;
	}
	/*else
	{
		int nSel = m_buff.indexOf("\r\n\r\n");
		if (nSel == -1)
			return QByteArray();
		return m_buff.mid(nSel + 4);
	}*/
}

QString XQHttp::header_recv() const
{
	int nSel = m_buff.indexOf("\r\n\r\n");
	if (nSel == -1)
		return QString();
	return m_buff.left(nSel + 4);
}

size_t XQHttp::currentContentLength()
{
	int nSel = m_buff.indexOf("\r\n\r\n");
	if (nSel == -1)//数据头有没有获取全
		return 0;
	auto count = m_buff.count()-nSel-4;
	return count;
}

const QByteArray& XQHttp::data() const
{
	return m_buff;
}

QString XQHttp::dataToString() const
{
	return QString(m_buff);
}

QString XQHttp::hostName() 
{
	return m_SendHead.host();
}

XQHttpHeadSend& XQHttp::sendHead()
{
	return m_SendHead;
}
